﻿using System;

namespace Xwltz.Framework.Helper
{
    public class DateTimeHelper
    {
        public static DateTime CurrDateTime = DateTime.Now;
        public static int CurrDay = DateTime.Now.Date.Day;
        public static int CurrMonth = DateTime.Now.Date.Month;
        public static int CurrYear = DateTime.Now.Date.Year;

        /// <summary>
        /// 当前时间
        /// </summary>
        public static DateTimeOffset Now => DateTimeOffset.Now;

        /// <summary>
        /// 当天零点时间，从 SystemTime.Now.Date 获得
        /// </summary>
        public static DateTime Today => Now.Date;

        /// <summary>
        /// 获取当前时间的 Ticks
        /// </summary>
        public static long NowTicks => Now.Ticks;

        /// <summary>
        /// Unix起始时间
        /// </summary>
        public static readonly DateTimeOffset BaseTime = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);

        //TODO：添加更多实用方法

        /// <summary>
        /// 获取 TimeSpan
        /// </summary>
        /// <param name="compareTime">当前时间 - compareTime</param>
        /// <returns></returns>
        public static TimeSpan NowDiff(DateTimeOffset compareTime)
        {
            return Now - compareTime;
        }

        /// <summary>
        /// 获取 TimeSpan
        /// </summary>
        /// <param name="compareTime">当前时间 - compareTime</param>
        /// <returns></returns>
        public static TimeSpan NowDiff(DateTime compareTime)
        {
            return Now.DateTime - compareTime;
        }

        /// <summary>
        /// 默认返回今天的开始日期和结束日期
        /// </summary>
        /// <returns></returns>
        public static CustomDate GetCustomDay()
        {
            var resutl = new CustomDate();
            var dtFirst = new DateTime(CurrYear, CurrMonth, CurrDay, 0, 0, 0);
            var dtLast = new DateTime(CurrYear, CurrMonth, CurrDay, 23, 59, 59);

            resutl.DtFirst = dtFirst;
            resutl.DtLast = dtLast;

            return resutl;
        }

        /// <summary>
        /// 转换微信DateTime时间到C#时间
        /// </summary>
        /// <param name="dateTimeFromXml">微信DateTime</param>
        /// <returns></returns>
        public static DateTime GetDateTimeFromXml(long dateTimeFromXml)
        {
            return GetDateTimeOffsetFromXml(dateTimeFromXml).LocalDateTime;
        }

        /// <summary>
        /// 转换微信DateTime时间到C#时间
        /// </summary>
        /// <param name="dateTimeFromXml">微信DateTime</param>
        /// <returns></returns>
        public static DateTime GetDateTimeFromXml(string dateTimeFromXml)
        {
            return GetDateTimeFromXml(long.Parse(dateTimeFromXml));
        }

        /// <summary>
        /// 转换微信DateTimeOffset时间到C#时间
        /// </summary>
        /// <param name="dateTimeFromXml">微信DateTime</param>
        /// <returns></returns>
        public static DateTimeOffset GetDateTimeOffsetFromXml(long dateTimeFromXml)
        {
            return BaseTime.AddSeconds(dateTimeFromXml).ToLocalTime();
        }

        /// <summary>
        /// 转换微信DateTimeOffset时间到C#时间
        /// </summary>
        /// <param name="dateTimeFromXml">微信DateTime</param>
        /// <returns></returns>
        public static DateTimeOffset GetDateTimeOffsetFromXml(string dateTimeFromXml)
        {
            return GetDateTimeFromXml(long.Parse(dateTimeFromXml));
        }

        /// <summary>
        /// 获取微信DateTime（UNIX时间戳）
        /// </summary>
        /// <param name="dateTime">时间</param>
        /// <returns></returns>
        [Obsolete("请使用 GetUnixDateTime(dateTime) 方法")]
        public static long GetWeixinDateTime(DateTime dateTime)
        {
            return GetUnixDateTime(dateTime);
        }

        /// <summary>
        /// 获取Unix时间戳
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static long GetUnixDateTime(DateTimeOffset dateTime)
        {
            return (long)(dateTime - BaseTime).TotalSeconds;
        }

        /// <summary>
        /// 获取Unix时间戳
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static long GetUnixDateTime(DateTime dateTime)
        {
            return (long)(dateTime.ToUniversalTime() - BaseTime).TotalSeconds;
        }

        /// <summary>
        /// 返回指定日期的开始日期和结束日期
        /// </summary>
        /// <returns></returns>
        public static CustomDate GetCustomDay(int day)
        {
            day = day <= 0 ? 1 : day;
            var resutl = new CustomDate();
            var dtFirst = new DateTime(CurrYear, CurrMonth, day, 0, 0, 0).AddDays(-1);
            var dtLast = new DateTime(CurrYear, CurrMonth, day, 23, 59, 59).AddDays(-1);

            resutl.DtFirst = dtFirst;
            resutl.DtLast = dtLast;

            return resutl;
        }

        /// <summary>
        /// 默认返回当前月的第一天和最后一天
        /// </summary>
        /// <returns></returns>
        public static CustomDate GetCustomMonth()
        {
            var resutl = new CustomDate();
            var dtFirst = new DateTime(DateTime.Now.Date.Year, DateTime.Now.Date.Month, 1, 0, 0, 0);
            var dtLast = new DateTime(DateTime.Now.Date.Year, DateTime.Now.Date.Month, 1, 23, 59, 59).AddMonths(1).AddDays(-1);

            resutl.DtFirst = dtFirst;
            resutl.DtLast = dtLast;

            return resutl;
        }

        /// <summary>
        /// 返回指定月份的第一天和最后一天
        /// </summary>
        /// <param name="month"></param>
        /// <returns></returns>
        public static CustomDate GetCustomMonth(int month)
        {
            month = month <= 0 ? 1 : month;
            var resutl = new CustomDate();
            var dtFirst = new DateTime(DateTime.Now.Date.Year, month, 1, 0, 0, 0);
            var dtLast = new DateTime(DateTime.Now.Date.Year, month, 1, 23, 59, 59).AddMonths(1).AddDays(-1);

            resutl.DtFirst = dtFirst;
            resutl.DtLast = dtLast;

            return resutl;
        }

        /// <summary>
        /// 默认返回今年的第一天和最后一天
        /// </summary>
        /// <returns></returns>
        public static CustomDate GetCustomYear()
        {
            var resutl = new CustomDate();
            var dtFirst = new DateTime(CurrYear, 1, 1, 0, 0, 0);
            var dtLast = new DateTime(CurrYear, 12, 31, 23, 59, 59);

            resutl.DtFirst = dtFirst;
            resutl.DtLast = dtLast;

            return resutl;
        }

        /// <summary>
        /// 返回指定年份的第一天和最后一天
        /// </summary>
        /// <param name="year"></param>
        /// <returns></returns>
        public static CustomDate GetCustomYear(int year)
        {
            year = year <= 0 ? 1 : year;
            var resutl = new CustomDate();
            var dtFirst = new DateTime(year, 1, 1, 0, 0, 0);
            var dtLast = new DateTime(year, 12, 31, 23, 59, 59);

            resutl.DtFirst = dtFirst;
            resutl.DtLast = dtLast;

            return resutl;
        }

        /// <summary>
        /// 根据日期获取星期名称
        /// </summary>
        /// <returns></returns>
        public static string GetWeekName()
        {
            string week;
            switch (CurrDateTime.DayOfWeek)
            {
                case DayOfWeek.Sunday:
                    week = "星期日";
                    break;

                case DayOfWeek.Monday:
                    week = "星期一";
                    break;

                case DayOfWeek.Tuesday:
                    week = "星期二";
                    break;

                case DayOfWeek.Wednesday:
                    week = "星期三";
                    break;

                case DayOfWeek.Thursday:
                    week = "星期四";
                    break;

                case DayOfWeek.Friday:
                    week = "星期五";
                    break;

                case DayOfWeek.Saturday:
                    week = "星期六";
                    break;
                default:
                    week = "未知";
                    break;
            }
            return week;
        }

        /// <summary>
        /// 根据日期获取星期名称
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static string GetWeekName(DateTime dt)
        {
            string week;
            switch (dt.DayOfWeek)
            {
                case DayOfWeek.Sunday:
                    week = "星期日";
                    break;

                case DayOfWeek.Monday:
                    week = "星期一";
                    break;

                case DayOfWeek.Tuesday:
                    week = "星期二";
                    break;

                case DayOfWeek.Wednesday:
                    week = "星期三";
                    break;

                case DayOfWeek.Thursday:
                    week = "星期四";
                    break;

                case DayOfWeek.Friday:
                    week = "星期五";
                    break;

                case DayOfWeek.Saturday:
                    week = "星期六";
                    break;
                default:
                    week = "未知";
                    break;
            }
            return week;
        }

        /// <summary>
        /// 根据日期获取星期数字
        /// </summary>
        /// <returns></returns>
        public static int GetWeekNumber()
        {
            int week;
            switch (CurrDateTime.DayOfWeek)
            {
                case DayOfWeek.Sunday:
                    week = 7;
                    break;

                case DayOfWeek.Monday:
                    week = 1;
                    break;

                case DayOfWeek.Tuesday:
                    week = 2;
                    break;

                case DayOfWeek.Wednesday:
                    week = 3;
                    break;

                case DayOfWeek.Thursday:
                    week = 4;
                    break;

                case DayOfWeek.Friday:
                    week = 5;
                    break;

                case DayOfWeek.Saturday:
                    week = 6;
                    break;
                default:
                    week = 0;
                    break;
            }
            return week;
        }

        /// <summary>
        /// 根据日期获取星期数字
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static int GetWeekNumber(DateTime dt)
        {
            int week;
            switch (dt.DayOfWeek)
            {
                case DayOfWeek.Sunday:
                    week = 7;
                    break;

                case DayOfWeek.Monday:
                    week = 1;
                    break;

                case DayOfWeek.Tuesday:
                    week = 2;
                    break;

                case DayOfWeek.Wednesday:
                    week = 3;
                    break;

                case DayOfWeek.Thursday:
                    week = 4;
                    break;

                case DayOfWeek.Friday:
                    week = 5;
                    break;

                case DayOfWeek.Saturday:
                    week = 6;
                    break;
                default:
                    week = 0;
                    break;
            }
            return week;
        }

        /// <summary>
        /// 根据日期获取月份天数
        /// </summary>
        /// <returns></returns>
        public static int GetDaysOfMonth()
        {
            var days = 0;
            switch (CurrDateTime.Month)
            {
                case 1:
                    days = 31;
                    break;

                case 2:
                    days = IsRuYear(CurrDateTime.Year) ? 29 : 28;
                    break;

                case 3:
                    days = 31;
                    break;

                case 4:
                    days = 30;
                    break;

                case 5:
                    days = 31;
                    break;

                case 6:
                    days = 30;
                    break;

                case 7:
                    days = 31;
                    break;

                case 8:
                    days = 31;
                    break;

                case 9:
                    days = 30;
                    break;

                case 10:
                    days = 31;
                    break;

                case 11:
                    days = 30;
                    break;

                case 12:
                    days = 31;
                    break;
            }
            return days;
        }

        /// <summary>
        /// 根据日期获取月份天数
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static int GetDaysOfMonth(DateTime dateTime)
        {
            var days = 0;
            switch (dateTime.Month)
            {
                case 1:
                    days = 31;
                    break;

                case 2:
                    days = IsRuYear(dateTime.Year) ? 29 : 28;
                    break;

                case 3:
                    days = 31;
                    break;

                case 4:
                    days = 30;
                    break;

                case 5:
                    days = 31;
                    break;

                case 6:
                    days = 30;
                    break;

                case 7:
                    days = 31;
                    break;

                case 8:
                    days = 31;
                    break;

                case 9:
                    days = 30;
                    break;

                case 10:
                    days = 31;
                    break;

                case 11:
                    days = 30;
                    break;

                case 12:
                    days = 31;
                    break;
            }
            return days;
        }

        /// <summary>
        /// 根据日期获取年份天数
        /// </summary>
        /// <returns></returns>
        public static int GetDaysOfYear()
        {
            return IsRuYear(CurrYear) ? 366 : 365;
        }

        /// <summary>
        /// 根据日期获取年份天数
        /// </summary>
        /// <param name="iYear"></param>
        /// <returns></returns>
        public static int GetDaysOfYear(int iYear)
        {
            return IsRuYear(iYear) ? 366 : 365;
        }

        /// <summary>
        /// 根据日期获取年份天数
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static int GetDaysOfYear(DateTime dt)
        {
            return IsRuYear(dt.Year) ? 366 : 365;
        }

        /// <summary>
        /// 根据日期获取是否是闰年
        /// </summary>
        /// <returns></returns>
        public static bool IsRuYear()
        {
            var iYear = CurrYear;
            return iYear % 400 == 0 || (iYear % 4 == 0 && iYear % 100 != 0);
        }

        /// <summary>
        /// 根据日期获取是否是闰年
        /// </summary>
        /// <param name="iYear"></param>
        /// <returns></returns>
        public static bool IsRuYear(int iYear)
        {
            return iYear % 400 == 0 || (iYear % 4 == 0 && iYear % 100 != 0);
        }

        /// <summary>
        /// 获取两时间差的元组
        /// </summary>
        /// <param name="dateTime1"></param>
        /// <param name="dateTime2"></param>
        /// <returns></returns>
        public static Tuple<int, int, int, int> DateDiff(DateTime dateTime1, DateTime dateTime2)
        {
            Tuple<int, int, int, int> tuple = null;
            try
            {
                var ts1 = new TimeSpan(dateTime1.Ticks);
                var ts2 = new TimeSpan(dateTime2.Ticks);
                var ts = ts1.Subtract(ts2).Duration();
                tuple = new Tuple<int, int, int, int>(ts.Days, ts.Hours, ts.Minutes, ts.Seconds);
            }
            catch
            {
                // ignored
            }

            return tuple;
        }

        /// <summary>
        /// 获取两时间差的文字显示效果 例：刚刚、5分钟前、1小时间、3天前
        /// </summary>
        /// <param name="dt1"></param>
        /// <param name="dt2"></param>
        /// <returns></returns>
        public static string TimeAgoStr(DateTime dt1, DateTime dt2)
        {
            var t = DateDiff(dt1, dt2);
            if (t == null)
                return "出错了";
            else if (t.Item1 > 0 && t.Item1 > 31)
                return dt1.ToString("yyyy-MM-dd");
            else if (t.Item1 > 0)
                return t.Item1 + "天前";
            else if (t.Item2 > 0)
                return t.Item2 + "小时前";
            else if (t.Item3 > 0)
                return t.Item3 + "分钟前";
            else
                return "刚刚";
        }
    }

    /// <summary>
    /// 自定义时间对象
    /// 返回开始时间和结束时间
    /// </summary>
    public class CustomDate
    {
        /// <summary>
        /// 开始时间
        /// </summary>
        public DateTime DtFirst { get; set; }
        /// <summary>
        /// 结束时间
        /// </summary>
        public DateTime DtLast { get; set; }
    }
}